use crate::{Downloadable, LibraryAllowed};
use model::{library, version::Libraries};
use std::path::Path;

impl LibraryAllowed for library::Library {
  fn allowed(&self) -> bool {
    let mut is_allowed = true;
    // have rules, then
    if self.rules.is_some() {
      for rule in self.rules.as_ref().unwrap() {
        if rule.os.name == "osx" && !cfg!(target_os = "macos") {
          is_allowed = false;
          break;
        } else if rule.os.name == "linux" && !cfg!(target_os = "linux") {
          is_allowed = false;
          break;
        } else if rule.os.name == "windows" && !cfg!(target_os = "windows") {
          is_allowed = false;
          break;
        }
      }
    }

    if self.name.contains("natives") {
      if self.name.contains("x86") && !cfg!(target_arch = "x86") {
        is_allowed = false;
      } else if self.name.contains("arm64") && !cfg!(target_arch = "aarch64") {
        is_allowed = false;
      } else if !cfg!(target_arch = "x86_64") {
        is_allowed = false
      }
    }

    is_allowed
  }
}

impl Downloadable for Libraries {
  fn download(
    &self,
    game_dir: &Path,
  ) -> Result<(), Box<dyn std::error::Error>> {
    println!("Downloading libraries");

    let libraries_dir = &game_dir.join("libraries");

    if !libraries_dir.exists() {
      std::fs::create_dir_all(libraries_dir)?;
    }

    for library in self {
      if !library.allowed() {
        continue;
      }

      let library_file = &library.downloads.artifact.path;

      let library_path = &libraries_dir.join(library_file);

      if !library_path.parent().unwrap().exists() {
        std::fs::create_dir_all(library_path.parent().unwrap())?;
      }

      if library_path.exists() {
        if crate::sha1(library_path)?.eq(&library.downloads.artifact.sha1) {
          continue;
        } else {
          std::fs::remove_file(library_path)?;
        }
      }

      let url = &library.downloads.artifact.url;

      println!("Downloading library: {}", url);

      let bytes = crate::get(url)?.bytes()?;

      std::fs::write(library_path, bytes)?;
    }

    Ok(())
  }
}
